#include "capture.hpp"

#undef LOG_TAG
#define LOG_TAG "Capture"

int CaptureInterface::init() {
    _capture = std::make_shared<cv::VideoCapture>();
    _capture->open(0, cv::CAP_V4L);  // ("/dev/video0", cv::CAP_V4L);
    CHECK(_capture->isOpened()) << "Create Capture Failed." << LOG_END;

    _capture->set(cv::CAP_PROP_FOURCC, cv::VideoWriter::fourcc('M', 'J', 'P', 'G'));
    _capture->set(cv::CAP_PROP_FPS, 60);
    _capture->set(cv::CAP_PROP_FRAME_WIDTH, 320);
    _capture->set(cv::CAP_PROP_FRAME_HEIGHT, 240);

    LOG_I << ">>> width  = " << _capture->get(cv::CAP_PROP_FRAME_WIDTH) << LOG_END;
    LOG_I << ">>> height = " << _capture->get(cv::CAP_PROP_FRAME_HEIGHT) << LOG_END;
    LOG_I << ">>> fps    = " << _capture->get(cv::CAP_PROP_FPS) << LOG_END;
    LOG_I << "Create Capture Success." << LOG_END;

    return 0;
}
// 鍚�鍔ㄨ�嗛�戞崟鑾风嚎绋�
int CaptureInterface::start() {
    _loop = true;
    _worker_thread = std::thread(&CaptureInterface::run, this);

    log_i("Start!");
    return 0;
}
// 鍋滄�㈣�嗛�戞崟鑾风嚎绋嬪苟閲婃斁璧勬簮
int CaptureInterface::stop() {
    if (_capture->isOpened()) {
        _capture->release();
    }

    _loop = false;
    _worker_thread.join();
    _queue.ShutDown();

    log_i("Stop.");
    return 0;
}
// 鑾峰彇褰撳墠甯у浘鍍�
void CaptureInterface::get(cv::Mat &frame) { frame = _queue.Take().clone(); }
// 瑙嗛�戞崟鑾风嚎绋嬬殑涓诲惊鐜�
void CaptureInterface::run() {
    cv::Mat _frame;

    while (_loop) {
        if (_capture->read(_frame)) {// 璇诲彇涓€甯у浘鍍�
            // 鍥剧墖瑁佸壀 (600x400)  (妯�鍧愭爣鍋忕Щ淇�姝� - 5)
            // 暂时注释掉图片裁剪，避免ROI错误
            // _frame = _frame(cv::Rect(20, 0, 600, 400));

            // 缁樺埗鐢板瓧鏍硷細鍩哄噯绾�
            /*
            uint8_t rows = 400 / 40;
            uint8_t cols = 600 / 60;

            for (uint8_t i = 1; i < rows; i++) {
                cv::line(_frame, cv::Point(0, 40 * i), cv::Point(_frame.cols - 1, 40 * i), cv::Scalar(211, 211, 211), 1);
            }
            for (uint8_t i = 1; i < cols; i++) {
                if (i == cols / 2)
                    cv::line(_frame, cv::Point(60 * i, 0), cv::Point(60 * i, _frame.rows - 1), cv::Scalar(0, 0, 255), 1);
                else
                    cv::line(_frame, cv::Point(60 * i, 0), cv::Point(60 * i, _frame.rows - 1), cv::Scalar(211, 211, 211), 1);
            }
            */

            if (_queue.Size() > 20)
                _queue.Take();
            _queue.Put(_frame);
        } else {
            CHECK(false) << "UsbCamera read failed." << LOG_END;
        }

#undef LOG_TAG
#define LOG_TAG "System"

        // 缁撴潫绋嬪簭
        if (_kbhit_()) {
            char c = fgetc(stdin);
            if (c == 'q' || c == 'Q') {
                log_i("Exit...");
                _loop = false;
                _launch = false;
            }
            if (c == 's' || c == 'S') {
                log_i("Pause...");
                _launch = false;
            }
            if (c == 'w' || c == 'W') {
                log_i("Run!");
                _launch = true;
            }
        }

        std::this_thread::sleep_for(std::chrono::milliseconds(1));// 浼戠湢1姣�绉�
    }
}

// 妫€娴嬮敭鐩樿緭鍏� - 闈為樆濉炴柟寮忔�€鏌ユ槸鍚︽湁鎸夐敭杈撳叆
// 浣跨敤select绯荤粺璋冪敤瀹炵幇闈為樆濉炵殑鏍囧噯杈撳叆妫€娴�
bool CaptureInterface::_kbhit_() {
    // 璁剧疆select瓒呮椂鏃堕棿涓�0锛屽疄鐜伴潪闃诲��
    struct timeval tv = {0L, 0L};  // {绉�, 寰�绉拀 閮借�句负0琛ㄧず绔嬪嵆杩斿洖
    
    // 鍒濆�嬪寲鏂囦欢鎻忚堪绗﹂泦鍚�
    fd_set fds;  // 鐢ㄤ簬瀛樺偍瑕佺洃鍚�鐨勬枃浠舵弿杩扮��
    FD_ZERO(&fds);  // 娓呯┖鏂囦欢鎻忚堪绗﹂泦鍚�
    FD_SET(0, &fds);  // 灏嗘爣鍑嗚緭鍏�(fd=0)鍔犲叆鍒扮洃鍚�闆嗗悎
    
    // 璋冪敤select妫€娴嬫爣鍑嗚緭鍏ユ槸鍚︽湁鏁版嵁鍙�璇�
    // 鍙傛暟璇存槑锛�1=鏈€澶ф枃浠舵弿杩扮��+1锛宖ds=瑕佺洃鍚�鐨勫彲璇绘枃浠舵弿杩扮�﹂泦鍚�
    // NULL=涓嶇洃鍚�鍙�鍐欏拰寮傚父锛宼v=瓒呮椂鏃堕棿
    return select(1, &fds, NULL, NULL, &tv);  // 杩斿洖鍊�>0琛ㄧず鏈夎緭鍏�
}
